home *** CD-ROM | disk | FTP | other *** search
Wrap
/* File: MouseModule.c Contains: HID Module for USB Mouse Version: xxx put version here xxx Copyright: © 1997-1999 by Apple Computer, Inc., all rights reserved. */ #include <Types.h> #include <Devices.h> #include <processes.h> #include <DriverServices.h> #include <USB.h> #include <LowMem.h> #include "MouseModule.h" usbMousePBStruct myMousePB; void InitParamBlock(USBReference theInterfaceRef, USBPB * paramblock) { paramblock->usbReference = theInterfaceRef; paramblock->pbVersion = kUSBCurrentPBVersion; paramblock->usb.cntl.WIndex = 0; paramblock->usb.cntl.WValue = 0; paramblock->usbBuffer = nil; paramblock->usbActCount = 0; paramblock->usbReqCount = 0; paramblock->usbFlags = 0; paramblock->usbOther = 0; paramblock->usbStatus = noErr; } Boolean immediateError(OSStatus err) { return((err != kUSBPending) && (err != noErr) ); } void MouseInitiateTransaction(USBPB *pb) { register usbMousePBStruct *pMousePB; OSStatus myErr; pMousePB = (usbMousePBStruct *)(pb); pMousePB->transDepth++; if (pMousePB->transDepth < 0) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth < 0 (initiation)", pMousePB->pb.usbRefcon ); } if (pMousePB->transDepth > 1) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth > 1 (initiation)", pMousePB->pb.usbRefcon ); } if (pMousePB->driverRemovalPending) { pMousePB->pb.usbRefcon = kReturnFromDriver; return; } switch(pMousePB->pb.usbRefcon & ~kRetryTransaction) { case kConfigureInterface: InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb); pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc; pMousePB->pb.usbRefcon |= kCompletionPending; myErr = USBConfigureInterface( &pMousePB->pb ); if(immediateError(myErr)) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kConfigureInterface - immediate error", myErr); pMousePB->pb.usbRefcon = kReturnFromDriver; } break; case kSetProtocol: InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb); pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface); pMousePB->pb.usb.cntl.BRequest = kHIDRqSetProtocol; pMousePB->pb.usb.cntl.WValue = kHIDBootProtocolValue; pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber; pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc; pMousePB->pb.usbRefcon |= kCompletionPending; myErr = USBDeviceRequest(&pMousePB->pb); if (immediateError(myErr)) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kSetProtocol - immediate error", myErr); } break; case kSetIdleRequest: USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Do a SetIdle on non-Apple mice, as some 3rd party mice don't send reports on button up", pMousePB->pipeRef); InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb); pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface); pMousePB->pb.usb.cntl.BRequest = kHIDRqSetIdle; pMousePB->pb.usb.cntl.WValue = ((24/4)<<8); // force a read completion if idle for more than 24ms pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber; pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc; pMousePB->pb.usbRefcon |= kCompletionPending; myErr = USBDeviceRequest(&pMousePB->pb); if(immediateError(myErr)) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kSetIdleRequest - immediate error", myErr); } break; case kFindPipe: InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb); pMousePB->pb.usbFlags = kUSBIn; pMousePB->pb.usbClassType = kUSBInterrupt; pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc; pMousePB->pb.usbRefcon |= kCompletionPending; myErr = USBFindNextPipe( &pMousePB->pb ); if((immediateError(myErr)) || (pMousePB->pb.usbBuffer == nil)) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kFindPipe - immediate error", myErr); pMousePB->pb.usbRefcon = kReturnFromDriver; } break; case kClearFeature: USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Do a clear feature on the interrupt endpoint", pMousePB->pipeRef); InitParamBlock(pMousePB->pipeRef, &pMousePB->pb); pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBEndpoint); pMousePB->pb.usb.cntl.BRequest = kUSBRqClearFeature; pMousePB->pb.usb.cntl.WValue = kUSBFeatureEndpointStall; pMousePB->pb.usbFlags = kUSBAddressRequest; /* kUSBAddressRequest asks the USL to do a translation of piperef to endpoint number */ pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc; pMousePB->pb.usbRefcon |= kCompletionPending; myErr = USBDeviceRequest(pb); if(immediateError(myErr)) { USBExpertFatalError(pMousePB->pb.usbReference, kUSBInternalErr, kMouseModuleName": kClearFeature - immediate error", myErr); } break; case kReadInterruptPipe: InitParamBlock(pMousePB->pipeRef, &pMousePB->pb); pMousePB->pb.usbBuffer = (Ptr)pMousePB->hidReport; pMousePB->pb.usbReqCount = pMousePB->maxPacketSize; pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber; pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc; pMousePB->pb.usbRefcon |= kCompletionPending; myErr = USBIntRead(&pMousePB->pb); if(immediateError(myErr)) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": Read Interrupt Pipe (ImmediateError)", myErr); } break; default: USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": Transaction initiated with bad refcon value", pMousePB->pb.usbRefcon); pMousePB->pb.usbRefcon = kUndefined + kReturnFromDriver; break; } // At this point the control is returned to the system. If a USB transaction // has been initiated, then it will call the Complete procs // (below) to handle the results of the transaction. } void MouseCompletionProc(USBPB *pb) { register usbMousePBStruct *pMousePB; unsigned char * errstring; USBPipeState pipeState; pMousePB = (usbMousePBStruct *)(pb); pMousePB->transDepth--; if (pMousePB->transDepth < 0) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth < 0 (completion)", pMousePB->pb.usbRefcon ); } if (pMousePB->transDepth > 1) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth > 1 (completion)", pMousePB->pb.usbRefcon ); } if(pMousePB->pb.usbStatus != noErr) // was there an error? { switch(pMousePB->pb.usbRefcon & 0x0fff) // yes, so show where the error occurred { case kSetProtocol: errstring = kMouseModuleName": Error during kSetProtocol"; break; case kSetIdleRequest: errstring = kMouseModuleName": Error during kSetIdleRequest"; break; case kConfigureInterface: errstring = kMouseModuleName": Error during kConfigureInterface"; break; case kFindPipe: errstring = kMouseModuleName": Error during kFindPipe"; break; case kClearFeature: errstring = kMouseModuleName": Error during kClearFeature"; break; case kReadInterruptPipe: { errstring = kMouseModuleName": Error during ReadInterruptPipe"; LMSetMouseButtonState(0x80); // release any possibly held-down mouse button break; } default: errstring = kMouseModuleName": Error occurred, but state is unknown"; break; }; USBExpertFatalError(pMousePB->interfaceRef, pMousePB->pb.usbStatus, errstring, (pMousePB->pb.usbRefcon & 0x0fff)); pMousePB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver); // set up to retry the transaction pMousePB->pb.usbRefcon |= kRetryTransaction; pMousePB->retryCount--; if ((pMousePB->retryCount == 1) && ((pMousePB->pb.usbRefcon&pMousePB->pb.usbRefcon & 0x0fff) == kSetIdleRequest)) { USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Device doesn't accept SetIdle", pMousePB->interfaceRef); pMousePB->pb.usbRefcon = kFindPipe; pMousePB->pb.usbStatus = noErr; } else { if ((!pMousePB->retryCount) || (pMousePB->pb.usbStatus == kUSBAbortedError)) // have we exhausted the retries? { // or received an abort? USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Pipe abort or unable to recover from error", pMousePB->interfaceRef); pMousePB->pb.usbRefcon = kReturnFromDriver; // if so, just exit. pMousePB->intPipeAborted = true; } else // if it didn't abort and there's retries left, then... { if (pMousePB->pipeRef) // check if the pipe is open. { USBGetPipeStatusByReference(pMousePB->pipeRef, &pipeState); // yes, so what it's state? if (pipeState != kUSBActive) // if it's not active, try to clear it. It might be stalled... { USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Pipe is open and stalled, clearing stall...", pMousePB->interfaceRef); USBClearPipeStallByReference(pMousePB->pipeRef); } } } } } else { pMousePB->pb.usbRefcon &= ~kRetryTransaction; pMousePB->retryCount = kMouseRetryCount; } if (pMousePB->pb.usbRefcon & kCompletionPending) { pMousePB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver); switch(pMousePB->pb.usbRefcon) { case kConfigureInterface: pMousePB->pb.usbRefcon = kSetProtocol; break; case kSetProtocol: if (kVendorID_AppleComputer == USBToHostWord(pMousePB->deviceDescriptor.vendor) ) { pMousePB->pb.usbRefcon = kFindPipe; } else { pMousePB->pb.usbRefcon = kSetIdleRequest; } break; case kSetIdleRequest: pMousePB->pb.usbRefcon = kFindPipe; break; case kFindPipe: pMousePB->maxPacketSize = pMousePB->pb.usb.cntl.WValue; pMousePB->pipeRef = pMousePB->pb.usbReference; pMousePB->pb.usbRefcon = kReadInterruptPipe; break; case kReadInterruptPipe: if (myMousePB.pNotificationRoutine) { (*myMousePB.pNotificationRoutine)(myMousePB.notificationRefcon, pMousePB->pb.usbActCount, (void *)pMousePB->hidReport, myMousePB.interfaceRef); } pMousePB->pb.usbRefcon = kReadInterruptPipe; break; default: USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": Transaction completed with bad refcon value", pMousePB->pb.usbRefcon ); pMousePB->pb.usbRefcon = kUndefined + kReturnFromDriver; break; } } if (!(pMousePB->pb.usbRefcon & kReturnFromDriver) && (!pMousePB->driverRemovalPending)) MouseInitiateTransaction(pb); } void InterfaceEntry(UInt32 interfacenum, USBInterfaceDescriptorPtr pInterfaceDescriptor, USBDeviceDescriptorPtr pDeviceDescriptor, USBReference theInterfaceRef) { #pragma unused (interfacenum) static Boolean beenThereDoneThat = false; if(beenThereDoneThat) { USBExpertFatalError(theInterfaceRef, kUSBInternalErr, kMouseModuleName" is not reentrant", 0); return; } beenThereDoneThat = true; // DebugStr("\pIn Mouse Interface Entry routine"); myMousePB.driverRemovalPending = false; myMousePB.intPipeAborted = false; myMousePB.deviceDescriptor = *pDeviceDescriptor; myMousePB.interfaceDescriptor = *pInterfaceDescriptor; myMousePB.transDepth = 0; myMousePB.retryCount = kMouseRetryCount; myMousePB.pSHIMInterruptRoutine = nil; myMousePB.pSavedInterruptRoutine = nil; myMousePB.notificationRefcon = 0; myMousePB.pNotificationRoutine = NotifyRegisteredHIDUser; myMousePB.interfaceRef = theInterfaceRef; myMousePB.pipeRef = nil; InitParamBlock(theInterfaceRef, &myMousePB.pb); myMousePB.pb.usbReference = theInterfaceRef; myMousePB.pb.pbLength = sizeof(usbMousePBStruct); myMousePB.pb.usbRefcon = kConfigureInterface; if ((myMousePB.deviceDescriptor.vendor == USB_CONSTANT16(0x046e)) && (myMousePB.deviceDescriptor.product == USB_CONSTANT16(0x6782))) { myMousePB.unitsPerInch = (Fixed)(100<<16); } else { myMousePB.unitsPerInch = (Fixed)(400<<16); } myMousePB.pCursorDeviceInfo = 0; USBHIDControlDevice(kHIDEnableDemoMode,0); MouseInitiateTransaction(&myMousePB.pb); }